from brain import Cell, Zone, Input, Output
from egg import Egg, CellGroup

# from env import Env
from PIL import Image
import random
import pygame


class Frog:
    eye = Zone(0, 0, 300)
    move_up = Zone(500, 50, 300)
    move_down = Zone(500, 100, 10)
    move_left = Zone(500, 150, 10)
    move_right = Zone(500, 200, 10)
    move_random = Zone(500, 300, 10)

    def __init__(self, x: int, y: int, egg: Egg) -> None:
        if egg.cell_groups is None:
            raise Exception("illegal egg cell groups")
        self.brain_radius: float = egg.brain_radius
        self.cells: list[Cell] = []
        self.x: int = x
        self.y: int = y
        self.energy: int = 10000
        self.egg: Egg = egg
        self.alive: bool = True
        self.move_count: int = 0
        self.img: Image
        self.allow_variation = False

        for k in range(len(egg.cell_groups)):
            g = egg.cell_groups[k]
            for i in range(g.cell_qty):
                c = Cell()
                c.inputs = [Input() for i in range(g.input_qty_per_cell)]
                for j in range(g.input_qty_per_cell):
                    c.inputs[j].cell = c
                    Zone.copyXY(
                        Frog.random_pos_in_zone(g.group_input_zone), c.inputs[j]
                    )
                    c.inputs[j].radius = g.cell_input_radius
                c.outputs = [Output() for i in range(g.output_qty_per_cell)]
                for j in range(g.output_qty_per_cell):
                    c.outputs[j].cell = c
                    Zone.copyXY(
                        Frog.random_pos_in_zone(g.group_input_zone), c.outputs[j]
                    )
                    c.outputs[j].radius = g.cell_output_radius
                self.cells.append(c)

    def active(self, env) -> bool:
        if not self.alive:
            return False
        if (
            self.x < 0
            or self.x >= env.env_xsize
            or self.y < 0
            or self.y >= env.env_ysize
        ):
            self.alive = False
            return False
        for cell in self.cells:
            for output in cell.outputs:
                if self.move_up.nearby(output):
                    self.do_move_up(env)
                if self.move_down.nearby(output):
                    self.do_move_down(env)
                if self.move_left.nearby(output):
                    self.do_move_left(env)
                if self.move_right.nearby(output):
                    self.do_move_right(env)
                if self.move_random.nearby(output):
                    self.do_move_random(env)
        return True

    def check_food_and_eat(self, env):
        eat_food = False
        if (
            self.x >= 0
            and self.x < env.env_xsize
            and self.y > 0
            and self.y < env.env_ysize
        ):
            if env.foods[self.x][self.y] > 0:
                env.foods[self.x][self.y] = 0
                self.energy += 1000
                eat_food = True
        if eat_food:
            # print("eat food")
            pass

    def do_move_up(self, env):
        self.y += 1
        if self.y < 0 or self.y >= env.env_ysize:
            self.alive = False
            return
        self.check_food_and_eat(env)

    def do_move_down(self, env):
        self.y -= 1
        if self.y < 0 or self.y >= env.env_ysize:
            self.alive = False
            return
        self.check_food_and_eat(env)

    def do_move_left(self, env):
        self.x -= 1
        if self.x < 0 or self.y >= env.env_xsize:
            self.alive = False
            return
        self.check_food_and_eat(env)

    def do_move_right(self, env):
        self.x += 1
        if self.x < 0 or self.y >= env.env_xsize:
            self.alive = False
            return
        self.check_food_and_eat(env)

    def do_move_random(self, env):
        rand = random.choice(
            [self.do_move_up, self.do_move_down, self.do_move_left, self.do_move_right]
        )
        rand(env)

    def lay_egg(self):
        if random.randint(1, 100) > 25:
            self.allow_variation = False
        else:
            self.allow_variation = True
        new_egg = Egg()
        new_egg.brain_radius = self.percent5(self.egg.brain_radius)
        cell_groups = [CellGroup() for i in range(len(self.egg.cell_groups))]
        new_egg.cell_groups = cell_groups
        for i in range(len(cell_groups)):
            c = CellGroup()
            cell_groups[i] = c
            old_g = self.egg.cell_groups[i]
            c.group_input_zone = Zone(
                self.percent5(old_g.group_input_zone.x),
                self.percent5(old_g.group_input_zone.y),
                self.percent5(old_g.group_input_zone.radius),
            )
            c.group_output_zone = Zone(
                self.percent5(old_g.group_output_zone.x),
                self.percent5(old_g.group_output_zone.y),
                self.percent5(old_g.group_output_zone.radius),
            )
            c.cell_qty = round(self.percent5(old_g.cell_qty))
            c.cell_input_radius = self.percent1(old_g.cell_input_radius)
            c.cell_output_radius = self.percent1(old_g.cell_output_radius)
            c.input_qty_per_cell = round(self.percent5(old_g.input_qty_per_cell))
            c.output_qty_per_cell = round(self.percent5(old_g.output_qty_per_cell))
        return new_egg

    def random_pos_in_zone(z: Zone):
        return Zone(
            z.x - z.radius + z.radius * 2 * random.random(),
            z.y - z.radius + z.radius * 2 * random.random(),
            0,
        )

    def percent1(self, f: float):
        if not self.allow_variation:
            return f
        return f * (0.99 + random.random() * 0.02)

    def percent5(self, f: float):
        if not self.allow_variation:
            return f
        return f * (0.95 + random.random() * 0.1)

    def show(self, img, screen: pygame.Surface):
        if not self.alive:
            return
        # screen.blit(
        #     img,
        #     (self.x - 8, self.y - 8),
        # (16, 16)
        # )
        # pygame.draw.circle(screen, "red", (self.x - 8, self.y - 8), 2, 1)
        pygame.draw.circle(screen, "green", (self.x, self.y), 5)
